package com.magicmovie.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.DateUtil;
import com.aliyun.oss.model.*;
import com.aliyuncs.exceptions.ClientException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @auther lee
 * @createTime 2018年01月26日 10时54分
 * @discription
 */
@Component
public class OSSClientUtils {
    @Value("${oss.endpoint}")
    private String endpoint;

    @Value("${oss.accessKeyId}")
    private String accessKeyId;

    @Value("${oss.accessKeySecret}")
    private String accessKeySecret;

    @Value("${oss.bucketNameAvatar}")
    private String bucketNameAvatar;

    @Value("${oss.imagePath}")
    private String imagePath;

    private OSSClient ossClient;
    //创建线程池
    private ExecutorService executorService = Executors.newFixedThreadPool(100);//创建一个100根线程的线程池


    public List uploadImgs(MultipartFile[] files) throws Exception {
        List<String> urls = new ArrayList<>();
        for (MultipartFile file : files) {
            String url = uploadImg2Oss(file);
            urls.add(url);
        }
        return urls;
    }

    public String uploadImg2Oss(MultipartFile file) throws Exception {
        if (ossClient == null) {
            ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        }
        String originalFilename = file.getOriginalFilename();
        String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        Random random = new Random();
        String fileUrl = random.nextInt(10000) + System.currentTimeMillis() + substring;
        try {
            InputStream inputStream = file.getInputStream();
            this.uploadFile2OSS(inputStream, fileUrl, imagePath);
        } catch (Exception e) {
            throw new Exception("图片上传失败");
        }
        if (!org.apache.commons.lang.StringUtils.isEmpty(fileUrl)) {
            String[] split = fileUrl.split("/");
            return this.getUrl(this.imagePath + split[split.length - 1]);
        }
        return null;
    }

//
//    public String uploadImg2Oss(InputStream in, String fileName, String filedir) throws IOException {
//        if (ossClient == null) {
//            ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
//        }
//        String name=DateUtil.formatIso8601Date(new Date());
//        try {
//            this.uploadFile2OSS(in, fileName+name, filedir);
//        } catch (Exception e) {
//            throw new IOException("图片上传失败");
//        }
//        if (!StringUtils.isEmpty(fileName)) {
//            String[] split = fileName.split("/");
//            return this.getUrl(filedir + split[split.length - 1]);
//        }
//        return null;
//    }

    /**
     * 断点续传
     */

    void uploadPartFile(String key, String uploadFile) {

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketNameAvatar, key);
            // The local file to upload---it must exist.
            uploadFileRequest.setUploadFile(uploadFile);
            // Sets the concurrent upload task number to 5.
            uploadFileRequest.setTaskNum(5);
            // Sets the part size to 1MB.
            uploadFileRequest.setPartSize(1024 * 1024 * 1);
            // Enables the checkpoint file. By default it's off.
            uploadFileRequest.setEnableCheckpoint(true);

            UploadFileResult uploadResult = ossClient.uploadFile(uploadFileRequest);

            CompleteMultipartUploadResult multipartUploadResult = uploadResult.getMultipartUploadResult();
            System.out.println(multipartUploadResult.getETag());

        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason.");
            System.out.println("Error Message: " + oe.getErrorCode());
            System.out.println("Error Code:       " + oe.getErrorCode());
            System.out.println("Request ID:      " + oe.getRequestId());
            System.out.println("Host ID:           " + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message: " + ce.getMessage());
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            ossClient.shutdown();
        }
    }


    /**
     * 上传到OSS服务器  如果同名文件会覆盖服务器上的
     *
     * @param instream 文件流
     * @param fileName 文件名称 包括后缀名
     * @return 出错返回"" ,唯一MD5数字签名
     */
    public String uploadFile2OSS(InputStream instream, String fileName, String filedir) {
        String ret = "";
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            String bucketName = bucketNameAvatar;

            //上传文件
            PutObjectResult putResult = ossClient.putObject(bucketName, filedir + fileName, instream, objectMetadata);
            ret = putResult.getETag();
        } catch (IOException e) {
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * Description: 判断OSS服务文件上传时文件的contentType
     *
     * @param FilenameExtension 文件后缀
     * @return String
     */
    public static String getcontentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpeg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpeg";
    }

    /**
     * 获得url链接
     *
     * @param key
     * @return
     */
    public String getUrl(String key) {
        // 设置URL过期时间为50年  3600l* 1000*24*365*50
        Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24 * 365 * 50);
        // 生成URL
        String bucketName = bucketNameAvatar;
        URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
        if (url != null) {
            return url.toString();
        }
        return null;
    }


    /**
     * 获得制定目录下的所有文件
     *
     * @param path
     * @return
     */
    public List<OSSObjectSummary> getFiles(String path) {
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        // 列举文件。 如果不设置KeyPrefix，则列举存储空间下所有的文件。KeyPrefix，则列举包含指定前缀的文件。
        ObjectListing objectListing = ossClient.listObjects(bucketNameAvatar, path);
        List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
        return sums;
    }

    /**
     * 移动指定文件到指定目录
     *
     * @return
     */
    public void moveFile(final String sourceKey, final String targetKey) {

        executorService.execute(new Runnable() {
            public void run() {
                OSS client = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
                try {
                    /*
                     * Claim a new upload id for your target bucket
                     */
                    InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(bucketNameAvatar, targetKey);
                    InitiateMultipartUploadResult initiateMultipartUploadResult = client.initiateMultipartUpload(initiateMultipartUploadRequest);
                    String uploadId = initiateMultipartUploadResult.getUploadId();

                    /*
                     * Calculate how many parts to be divided
                     */
                    final long partSize = 5 * 1024 * 1024L;   // 5MB
                    ObjectMetadata metadata = client.getObjectMetadata(bucketNameAvatar, sourceKey);
                    long objectSize = metadata.getContentLength();
                    int partCount = (int) (objectSize / partSize);
                    if (objectSize % partSize != 0) {
                        partCount++;
                    }
                    if (partCount > 10000) {
                        throw new RuntimeException("Total parts count should not exceed 10000");
                    } else {
                        System.out.println("Total parts count " + partCount + "\n");
                    }

                    /*
                     * Upload multiparts by copy mode
                     */
                    System.out.println("Begin to upload multiparts by copy mode to OSS\n");
                    List<PartETag> partETags = new ArrayList<PartETag>();
                    for (int i = 0; i < partCount; i++) {
                        long startPos = i * partSize;
                        long curPartSize = (i + 1 == partCount) ? (objectSize - startPos) : partSize;

                        UploadPartCopyRequest uploadPartCopyRequest = new UploadPartCopyRequest(bucketNameAvatar, sourceKey, bucketNameAvatar, targetKey);
                        uploadPartCopyRequest.setUploadId(uploadId);
                        uploadPartCopyRequest.setPartSize(curPartSize);
                        uploadPartCopyRequest.setBeginIndex(startPos);
                        uploadPartCopyRequest.setPartNumber(i + 1);

                        UploadPartCopyResult uploadPartCopyResult = client.uploadPartCopy(uploadPartCopyRequest);
                        System.out.println("\tPart#" + uploadPartCopyResult.getPartNumber() + " done\n");
                        partETags.add(uploadPartCopyResult.getPartETag());
                    }

                    /*
                     * Complete to upload multiparts
                     */
                    System.out.println("Completing to upload multiparts\n");
                    CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
                            bucketNameAvatar, targetKey, uploadId, partETags);
                    client.completeMultipartUpload(completeMultipartUploadRequest);
                    client.deleteObject(bucketNameAvatar, sourceKey);
                    /*
                     * Fetch the object that newly created at the step below.
                     */
                    System.out.println("Fetching an object");
                    //      client.getObject(new GetObjectRequest(targetBucketName, targetKey), new File(localFilePath));

                } catch (OSSException oe) {
                    System.out.println("Caught an OSSException, which means your request made it to OSS, "
                            + "but was rejected with an error response for some reason.");
                    System.out.println("Error Message: " + oe.getErrorCode());
                    System.out.println("Error Code:       " + oe.getErrorCode());
                    System.out.println("Request ID:      " + oe.getRequestId());
                    System.out.println("Host ID:           " + oe.getHostId());
                } finally {
                    /*
                     * Do not forget to shut down the client finally to release all allocated resources.
                     */
                    client.shutdown();
                }
            }
        });
    }

    public void remove(String objectName) {
        // Endpoint以杭州为例，其它Region请按实际情况填写。
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        // 删除文件。
        ossClient.deleteObject(bucketNameAvatar, objectName);
        // 关闭OSSClient。
        ossClient.shutdown();
    }

}

